home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
CAVE.ZIP
/
LDOOM3.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-07-17
|
44KB
|
1,543 lines
PROGRAM LDOOM;
{$G+}
uses variable,pong2,thegraph,dos,pcx,crt,ctvoice;
(*---------------------- Procedure init_d_sound ----------------------------*)
PROCEDURE fade;
VAR counter:integer;
facts:rgb_color_typ;
done:boolean;
BEGIN
REPEAT
FOR counter:=1 TO 255 DO
BEGIN
get_palette_register(counter,facts);
IF facts.red-5<0 THEN facts.red:=0 ELSE facts.red:=facts.red-5;
IF facts.blue-5<0 THEN facts.blue:=0 ELSE facts.blue:=facts.blue-5;
IF facts.green-5<0 THEN facts.green:=0 ELSE facts.green:=facts.green-5;
IF (facts.red=0) AND (facts.green=0) AND (facts.blue=0) THEN done:=true
ELSE done:=false;
set_palette_register(counter,facts);
END;
delay(75);
UNTIL done;
END;
PROCEDURE init_sound;
BEGIN
loadctdriver('ct-voice.drv');
useport($220);
useirq(5);
usechannel(1);
initializedriver;
END;
(*------------------- Procedure play_sound --------------------------------*)
PROCEDURE play_sound(sound:voctp);
VAR sample:voctp;
begin
stopvprocess;
sbioresult:=callok;
if sbioresult=callok then begin
if statusword=0 then playblock(sound);
end;
end;
(*------------------PROCEDURE SEARCH-----------------------------------*)
PROCEDURE search(first:enemypointer; xer,yer:byte; var Last,Next:enemypointer);
BEGIN
next:=first^.link;
last:=first;
while ((next^.enemy.xpos<>xer) OR (next^.enemy.ypos<>yer)) AND
(next^.link<>nil) do
begin
last:=next;
next:=next^.link
end;
END;
PROCEDURE del_enemy(first:enemypointer; xer,yer:byte);
VAR last,next:enemypointer;
BEGIN
next:=first^.link;
if next<>nil THEN
BEGIN
search(first,xer,yer,last,next);
if (next^.enemy.xpos=xer) AND (next^.enemy.ypos=yer) THEN
BEGIN
last^.link:=next^.link;
dispose(next);
END
END;
END;
PROCEDURE add_enemy(VAR head:enemypointer; num,xer,yer:byte);
var newnode:enemypointer;
begin
new(newnode);
newnode^.enemy.xpos:=xer;
newnode^.enemy.ypos:=yer;
newnode^.enemy.curframe:=1;
CASE num OF
11:BEGIN
newnode^.enemy.numhp:=3;
newnode^.enemy.daminflict:=3
END;
12:BEGIN
newnode^.enemy.numhp:=5;
newnode^.enemy.daminflict:=6
END;
END;
newnode^.link:=head^.link;
head^.link:=newnode;
END;
(*----------------------- Procedure Load_World ---------------------------*)
PROCEDURE Load_World(worldfile:string);
VAR infile:text;
row,column,times:INTEGER;
ch:char;
temp:integer;
res,ans:byte;
BEGIN
check_file(worldfile);
assign(infile,worldfile);
reset(infile);
for row:=0 TO WORLD_ROWS-1 DO
BEGIN
for column:=1 TO WORLD_COLUMNS DO
BEGIN
ans:=0;
FOR times:=1 TO 2 DO
BEGIN
read(infile,ch);
IF ch=' ' THEN res :=0
ELSE
val(ch,res,temp);
IF times=1 THEN res:=res*10;
ans:=ans+res
END;
IF ans>10 THEN add_enemy(enemylist,ans,column,world_rows-row);
world[world_rows-row,column] := ans;
END;
readln(infile);
END;
close(infile);
END;
(*------------- Procedure Save_World ----------------------------*)
PROCEDURE Save_World(position:word);
VAR infile:text;
row,column:INTEGER;
ch:char;
res:byte;
filename:string;
BEGIN
CASE position OF
1:filename:='Cave1.sav';
2:filename:='Cave2.sav';
3:filename:='Cave3.sav';
4:filename:='Cave4.sav';
5:filename:='Cave5.sav';
END;
assign(infile,filename);
rewrite(infile);
for row:=0 TO WORLD_ROWS-1 DO
BEGIN
for column:=1 TO WORLD_COLUMNS DO
BEGIN
res:=world[world_rows-row,column];
IF res=0 THEN ch:=' '
ELSE
BEGIN
str(res,filename);
ch:=filename[1];
END;
write(infile,ch);
END;
writeln(infile);
END;
close(infile);
END;
(*------------- Procedure Create_Scale_Data ---------------------*)
Procedure Create_Scale_Data(scale:INTEGER; VAR row:pcximage);
VAR y,roff,rseg,temp:INTEGER;
y_scale_index,y_scale_step:real;
BEGIN
y_scale_index:=0;
y_scale_step := 64/scale;
y_scale_index:=y_scale_index+y_scale_step;
roff:=ofs(row^); rseg:=seg(row^);
for y:=0 TO scale-1 DO
BEGIN
temp:=TRUNC((y_scale_index+0.5)) * CELL_X_SIZE;
move(temp,mem[rseg:roff+(y*2)],2);
if ( temp> 63*CELL_X_SIZE) THEN
BEGIN
temp := 63*CELL_X_SIZE;
move(temp,mem[rseg:roff+(y*2)],2);
END;
y_scale_index:=y_scale_index+y_scale_step;
END
END;
(*---------------------- Procedure Build_Tables --------------------------*)
PROCEDURE Build_Tables;
VAR temp,rad_angle:real;
scale:integer;
ang:INTEGER;
BEGIN
check_mem(tan_table,6*angle_360);
check_mem(inv_tan_table,6*angle_360);
check_mem(y_step,6*angle_360);
check_mem(x_step,6*angle_360);
check_mem(cos_table,6*angle_360);
check_mem(inv_cos_table,6*angle_360);
check_mem(inv_sin_table,6*angle_360);
toff:=ofs(tan_table^); tseg:=seg(tan_table^);
ioff:=ofs(inv_tan_table^); iseg:=seg(inv_tan_table^);
yoff:=ofs(y_step^); yseg:=seg(y_step^);
xoff:=ofs(x_step^); xseg:=seg(x_step^);
icoff:=ofs(inv_cos_table^); icseg:=seg(inv_cos_table^);
isoff:=ofs(inv_sin_table^); isseg:=seg(inv_sin_table^);
coff:=ofs(cos_table^); cseg:=seg(cos_table^);
FOR ang:=ANGLE_0 TO ANGLE_360 DO
BEGIN
rad_angle := ((3.72e-4)+ang*2*3.141592654/ANGLE_360);
temp:=sin(rad_angle)/cos(rad_angle);
move(temp,mem[tseg:toff+ang*6],6);
temp:=1/temp;
move(temp,mem[iseg:ioff+ang*6],6);
if (ang>=ANGLE_0) AND (ang<ANGLE_180) THEN
BEGIN
move(mem[tseg:toff+ang*6],temp,6);
temp:=ABS(temp*CELL_Y_SIZE);
move(temp,mem[yseg:yoff+ang*6],6)
END
else
BEGIN
move(mem[tseg:toff+ang*6],temp,6);
temp:=-(ABS(temp*CELL_Y_SIZE));
move(temp,mem[yseg:yoff+ang*6],6)
END;
if (ang>=ANGLE_90) AND (ang<ANGLE_270) THEN
BEGIN
move(mem[iseg:ioff+ang*6],temp,6);
temp:=-(ABS(temp*CELL_X_SIZE));
move(temp,mem[xseg:xoff+ang*6],6)
END
else
BEGIN
move(mem[iseg:ioff+ang*6],temp,6);
temp:=(ABS(temp*CELL_X_SIZE));
move(temp,mem[xseg:xoff+ang*6],6)
END;
temp:=1/cos(rad_angle);
move(temp,mem[icseg:icoff+ang*6],6);
temp:=1/sin(rad_angle);
move(temp,mem[isseg:isoff+ang*6],6);
END;
FOR ang:=-Angle_30 to Angle_30 DO
BEGIN
rad_angle := ((3.72e-4)+ang*2*3.141592654/ANGLE_360);
temp:=VERTICAL_SCALE/cos(rad_angle);
move(temp,mem[cseg:coff+((ang +ANGLE_30)*6)],6);
END;
for scale:=1 TO MAX_SCALE DO
BEGIN
check_mem(scales[scale],scale*2);
create_scale_data(scale,scales[scale]);
END;
END;
(*---------------------- Procedure free_scale_data -------------------*)
PROCEDURE free_scale_data;
VAR y:INTEGER;
bEGIN
FOR y:=1 TO MAX_SCALE DO
freemem(scales[y],y*2);
END;
(*----------------------- Procedure Render_Sliver ------------------------*)
PROCEDURE fast_render;
VAR soff,sseg:word;
BEGIN
soff:=ofs(sliver_texture^);
sseg:=seg(sliver_texture^);
asm
push si
push di
mov di, doff
mov dx,sliver_column
mov si,soff
mov bx,sliver_top
shl bx,8
mov ax,bx
shr bx,2
add bx,ax
add bx,sliver_ray
add di,bx
mov bx,sliver_clip
mov ax,sliver_scale
add ax,bx
@Sliver_Loop:
xchg dx,bx
mov es,sseg
mov cl, BYTE PTR es:[si+bx]
mov es,dseg
mov es:[di], cl
xchg dx,bx
mov cx,bx
mov dx,scaleoff
mov es,scaleseg
shl bx,1
add bx,dx
mov dx, WORD PTR es:[bx]
add dx,sliver_column
mov bx,cx
add di,320
inc bx
cmp bx, ax
jne @Sliver_Loop
pop di
pop si
END;
END;
PROCEDURE fast_render_blit;
VAR soff,sseg,goff,gseg:word;
BEGIN
soff:=ofs(sliver_texture^);
sseg:=seg(sliver_texture^);
asm
jmp @start
@draw_it:
mov es,dseg
mov es:[di], cl
jmp @begins
@start:
push si
push di
mov di, doff
mov dx,sliver_column
mov si,soff
mov bx,sliver_top
shl bx,8
mov ax,bx
shr bx,2
add bx,ax
add bx,sliver_ray
add di,bx
mov bx,sliver_clip
mov ax,sliver_scale
add ax,bx
@Sliver_Loop:
xchg dx,bx
mov es,sseg
mov cl, BYTE PTR es:[si+bx]
cmp cl,0
jne @draw_it
@begins:
xchg dx,bx
mov cx,bx
mov dx,scaleoff
mov es,scaleseg
shl bx,1
add bx,dx
mov dx, WORD PTR es:[bx]
add dx,sliver_column
mov bx,cx
add di,320
inc bx
cmp bx, ax
jne @Sliver_Loop
pop di
pop si
END;
END;
PROCEDURE hit_guy(xer,yer:word);
VAR next,last:enemypointer;
BEGIN
search(enemylist,xer,yer,next,last);
bloodon:=true;
IF sniper THEN last^.enemy.numhp:=0
ELSE
last^.enemy.numhp:=last^.enemy.numhp-1;
IF last^.enemy.numhp=0 THEN
BEGIN
IF last^.enemy.daminflict=6 THEN gatesdead:=true;
world[yer,xer]:=0;
play_sound(ugh);
del_enemy(enemylist,xer,yer);
END;
END;
PROCEDURE move_guy(guyx,guyy,playerx,playery:word);
VAR moved:boolean;
next,last:enemypointer;
BEGIN
playerx:=playerx SHR 6;
playery:=playery SHR 6;
search(enemylist,guyx,guyy,next,last);
moved:=false;
{ IF random(5)=3 THEN
BEGIN
IF (world[guyy,guyx-1]=0) AND (playerx<guyx) AND
((guyx-1<>playerx) OR (playery<>guyy)) THEN
BEGIN
moved:=true;
world[guyy,guyx]:=0;
world[guyy,guyx-1]:=11;
last^.enemy.xpos:=guyx-1;
END
ELSE
IF (world[guyy,guyx+1]=0) AND (playerx>guyx)
AND ((guyx+1<>playerx) OR (playery<>guyy)) THEN
BEGIN
moved:=true;
world[guyy,guyx]:=0;
world[guyy,guyx+1]:=11;
last^.enemy.xpos:=guyx+1;
END
ELSE
IF (world[guyy-1,guyx]=0) AND (playery<guyy)
AND ((guyy-1<>playery) OR (playerx<>guyx)) THEN
BEGIN
moved:=true;
world[guyy,guyx]:=0;
world[guyy-1,guyx]:=11;
last^.enemy.ypos:=guyy-1;
END
ELSE
IF (world[guyy+1,guyx]=0) AND (playery>guyy)
AND ((guyy+1<>playery) OR (playerx<>guyx)) THEN
BEGIN
moved:=true;
world[guyy,guyx]:=0;
world[guyy+1,guyx]:=11;
last^.enemy.ypos:=guyy+1;
END;
END;
IF moved THEN }
IF monster.cur_frame<3 THEN INC(monster.cur_frame)
ELSE monster.cur_frame:=1;
enmove:=true;
IF (guyx+1=playerx) OR (guyx-1=playerx) OR (guyy-1=playery)
OR (guyy+1=playery) THEN
IF (RANDOM(6)+1=3) THEN
BEGIN
monster.cur_frame:=4;
IF not(touch) THEN life:=life-3
END;
END;
PROCEDURE GUY_Caster(x,y,view_angle:LONGINT);
VAR
cell_x,cell_y,ray,casting,x_hit_type,y_hit_type,x_bound,y_bound,
next_y_cell,next_x_cell,xray,yray,x_delta,y_delta,xb_save,yb_save,
xi_save,yi_save,scale:INTEGER;
dist_x,dist_y:longint;
xi,yi,temp:REAL;
BEGIN
xray:=0;
yray:=0;
casting:=2;
view_angle:=view_angle-angle_30;
if (view_angle< 0) THEN view_angle:=ANGLE_360 + view_angle;
for ray:=319 downto 0 DO
BEGIN
if (view_angle >= ANGLE_0) AND (view_angle < ANGLE_180) THEN
BEGIN
y_bound := (CELL_Y_SIZE + (y AND $ffc0));
y_delta := CELL_Y_SIZE;
move(mem[iseg:ioff+(view_angle*6)],temp,6);
xi:=temp*(y_bound-y)+x;
next_y_cell := 0;
END
else
BEGIN
y_bound := (y AND $ffc0);
y_delta := -CELL_Y_SIZE;
move(mem[iseg:ioff+(view_angle*6)],temp,6);
xi := temp * (y_bound - y) + x;
next_y_cell := -1;
ENd;
if (view_angle < ANGLE_90) OR (view_angle >= ANGLE_270) THEN
BEGIN
x_bound := (CELL_X_SIZE + (x AND $ffc0));
x_delta := CELL_X_SIZE;
move(mem[tseg:toff+(view_angle*6)],temp,6);
yi:=temp*(x_bound-x)+y;
next_x_cell := 0;
END
else
BEGIN
x_bound := (x AND $ffc0);
x_delta := -CELL_X_SIZE;
move(mem[tseg:toff+(view_angle*6)],temp,6);
yi := temp * (x_bound - x) + y;
next_x_cell := -1;
END;
casting:= 2;
xray:= 0;
yray:=0;
while casting>0 DO
BEGIN
if (xray<>INTERSECTION_FOUND) THEN
BEGIN
cell_x := ( (x_bound+next_x_cell) SHR CELL_X_SIZE_FP);
cell_y := trunc(yi);
cell_y:=cell_y SHR CELL_Y_SIZE_FP;
x_hit_type:=world[cell_y,cell_x];
if (x_hit_type>0) THEN
BEGIN
move(mem[isseg:isoff+(view_angle*6)],temp,6);
dist_x := round((yi - y) * temp);
yi_save := trunc(yi);
xb_save := x_bound;
xray := INTERSECTION_FOUND;
dec(casting);
END
else
BEGIN
move(mem[yseg:yoff+(view_angle*6)],temp,6);
yi:=yi+temp;
x_bound:=x_bound+x_delta;
END;
END;
if (yray<>INTERSECTION_FOUND) THEN
BEGIN
cell_x :=trunc(xi);
cell_x:=cell_x SHR CELL_X_SIZE_FP;
cell_y := ( (y_bound + next_y_cell) SHR CELL_Y_SIZE_FP);
y_hit_type := world[cell_y,cell_x];
if (y_hit_type>0 ) THEN
BEGIN
move(mem[icseg:icoff+(view_angle*6)],temp,6);
dist_y := round((xi- x) * temp);
xi_save := trunc(xi);
yb_save := y_bound;
yray := INTERSECTION_FOUND;
dec(casting);
END
else
BEGIN
move(mem[xseg:xoff+(view_angle*6)],temp,6);
xi :=xi+temp;
y_bound :=y_bound+ y_delta;
END;
END;
END;
if (dist_x < dist_y) AND ((x_hit_type>10) OR (y_hit_type>10)) THEN
BEGIN
move(mem[cseg:coff+(ray*6)],temp,6);
scale := trunc((temp/dist_x));
if (scale>(MAX_SCALE)) THEN scale:=(MAX_SCALE);
scaleoff := ofs(scales[scale]^);
scaleseg := seg(scales[scale]^);
if (scale>WINDOW_HEIGHT) THEN
BEGIN
sliver_clip := (scale-WINDOW_HEIGHT) SHR 1;
scale:=WINDOW_HEIGHT;
END
else
sliver_clip := 0;
sliver_scale := scale;
CASE x_hit_type OF
11:sliver_texture:= monster.frames[monster.cur_frame];
12:sliver_texture:=gates.frames[1];
13:sliver_texture:=waldo.frames[1];
END;
sliver_column := (yi_save AND $003f);
sliver_top := WINDOW_MIDDLE - (scale SHR 1);
sliver_ray := ray;
IF (x_hit_type>10) AND
(((player_view_angle>=720) AND (player_view_angle<=1200))
OR ((player_view_angle>=1680) OR (player_view_angle<=240)))
THEN fast_Render_blit;
END
else
BEGIN
move(mem[cseg:coff+(ray*6)],temp,6);
scale := trunc((temp/dist_y));
if (scale>(MAX_SCALE)) THEN scale:=(MAX_SCALE);
scaleoff := ofs(scales[scale]^);
scaleseg := seg(scales[scale]^);
if (scale>WINDOW_HEIGHT) THEN
BEGIN
sliver_clip := (scale-WINDOW_HEIGHT) SHR 1;
scale:=WINDOW_HEIGHT;
END
else
sliver_clip := 0;
sliver_scale:= scale;
CASE y_hit_type OF
11:sliver_texture:= monster.frames[monster.cur_frame];
12:sliver_texture:=gates.frames[1];
13:sliver_texture:=waldo.frames[1];
END;
sliver_column:= (xi_save AND $003f);
sliver_top:= WINDOW_MIDDLE - (scale SHR 1);
sliver_ray:= ray;
IF (y_hit_type>10) AND
((player_view_angle>1200) AND (player_view_angle<1680)
OR (player_view_angle>240) AND (player_view_angle<720))
THEN fast_Render_blit;
END;
view_angle:=view_angle+1;
if (view_angle>=ANGLE_360) THEN view_angle:=0;
END;
END;
PROCEDURE Ray_Caster(x,y,view_angle:LONGINT);
VAR
cell_x,cell_y,ray,casting,x_hit_type,y_hit_type,x_bound,y_bound,
next_y_cell,next_x_cell,xray,yray,x_delta,y_delta,xb_save,yb_save,
xi_save,yi_save,scale:INTEGER;
dist_x,dist_y:longint;
xi,yi,temp:REAL;
BEGIN
xray:=0;
yray:=0;
casting:=2;
view_angle:=view_angle-angle_30;
if (view_angle< 0) THEN view_angle:=ANGLE_360 + view_angle;
for ray:=319 downto 0 DO
BEGIN
if (view_angle >= ANGLE_0) AND (view_angle < ANGLE_180) THEN
BEGIN
y_bound := (CELL_Y_SIZE + (y AND $ffc0));
y_delta := CELL_Y_SIZE;
move(mem[iseg:ioff+(view_angle*6)],temp,6);
xi:=temp*(y_bound-y)+x;
next_y_cell := 0;
END
else
BEGIN
y_bound := (y AND $ffc0);
y_delta := -CELL_Y_SIZE;
move(mem[iseg:ioff+(view_angle*6)],temp,6);
xi := temp * (y_bound - y) + x;
next_y_cell := -1;
ENd;
if (view_angle < ANGLE_90) OR (view_angle >= ANGLE_270) THEN
BEGIN
x_bound := (CELL_X_SIZE + (x AND $ffc0));
x_delta := CELL_X_SIZE;
move(mem[tseg:toff+(view_angle*6)],temp,6);
yi:=temp*(x_bound-x)+y;
next_x_cell := 0;
END
else
BEGIN
x_bound := (x AND $ffc0);
x_delta := -CELL_X_SIZE;
move(mem[tseg:toff+(view_angle*6)],temp,6);
yi := temp * (x_bound - x) + y;
next_x_cell := -1;
END;
casting:= 2;
xray:= 0;
yray:=0;
while casting>0 DO
BEGIN
if (xray<>INTERSECTION_FOUND) THEN
BEGIN
cell_x := ( (x_bound+next_x_cell) SHR CELL_X_SIZE_FP);
cell_y := trunc(yi);
cell_y:=cell_y SHR CELL_Y_SIZE_FP;
x_hit_type:=world[cell_y,cell_x];
IF not(enmove) AND (x_hit_type=11) THEN move_guy(cell_x,cell_y,x,y);
IF x_hit_type>10 THEN dg:=true;
if (x_hit_type>0) AND (x_hit_type<11) THEN
BEGIN
move(mem[isseg:isoff+(view_angle*6)],temp,6);
dist_x := round((yi - y) * temp);
yi_save := trunc(yi);
xb_save := x_bound;
xray := INTERSECTION_FOUND;
DEC(casting);
END
else
BEGIN
move(mem[yseg:yoff+(view_angle*6)],temp,6);
yi:=yi+temp;
x_bound:=x_bound+x_delta;
END;
END;
if (yray<>INTERSECTION_FOUND) THEN
BEGIN
cell_x :=trunc(xi);
cell_x:=cell_x SHR CELL_X_SIZE_FP;
cell_y := ( (y_bound + next_y_cell) SHR CELL_Y_SIZE_FP);
y_hit_type := world[cell_y,cell_x];
IF not(enmove) AND (y_hit_type=11) THEN move_guy(cell_x,cell_y,x,y);
IF y_hit_type>10 THEN dg:=true;
if (y_hit_type>0) AND (y_hit_type<11) THEN
BEGIN
move(mem[icseg:icoff+(view_angle*6)],temp,6);
dist_y := round((xi- x) * temp);
xi_save := trunc(xi);
yb_save := y_bound;
yray := INTERSECTION_FOUND;
DEC(casting);
END
else
BEGIN
move(mem[xseg:xoff+(view_angle*6)],temp,6);
xi :=xi+temp;
y_bound :=y_bound+ y_delta;
END;
END;
END;
if (dist_x < dist_y) THEN
BEGIN
move(mem[cseg:coff+(ray*6)],temp,6);
scale := trunc((temp/dist_x));
if (scale>(MAX_SCALE)) THEN scale:=(MAX_SCALE);
scaleoff := ofs(scales[scale]^);
scaleseg := seg(scales[scale]^);
if (scale>WINDOW_HEIGHT) THEN
BEGIN
sliver_clip := (scale-WINDOW_HEIGHT) SHR 1;
scale:=WINDOW_HEIGHT;
END
else
sliver_clip := 0;
sliver_scale := scale;
sliver_texture:= sprite.frames[x_hit_type];
sliver_column := (yi_save AND $003f);
sliver_top := WINDOW_MIDDLE - (scale SHR 1);
sliver_ray := ray;
fast_Render;
END
else
BEGIN
move(mem[cseg:coff+(ray*6)],temp,6);
scale := trunc((temp/dist_y));
if (scale>(MAX_SCALE)) THEN scale:=(MAX_SCALE);
scaleoff := ofs(scales[scale]^);
scaleseg := seg(scales[scale]^);
if (scale>WINDOW_HEIGHT) THEN
BEGIN
sliver_clip := (scale-WINDOW_HEIGHT) SHR 1;
scale:=WINDOW_HEIGHT;
END
else
sliver_clip := 0;
sliver_scale:= scale;
sliver_texture:= sprite.frames[y_hit_type+1];
sliver_column:= (xi_save AND $003f);
sliver_top:= WINDOW_MIDDLE - (scale SHR 1);
sliver_ray:= ray;
fast_Render;
END;
view_angle:=view_angle+1;
if (view_angle>=ANGLE_360) THEN view_angle:=0;
END;
END;
(*------------------ Procedure Draw_ground -------------------------------*)
PROCEDURE Draw_Ground;
BEGIN
move(mem[seg(floor^):ofs(floor^)],
mem[seg(double_buffer^):ofs(double_buffer^)],48640);
END;
(*--------------------- Function Get_Input ------------------------------*)
FUNCTION Get_Input:INTEGER;
VAR demo_data:char;
BEGIN
if (key_table[0]<>0) OR (key_table[1]<>0) OR (key_table[2]<>0)
OR (key_table[3]<>0) THEN
get_input:=1
else
get_input:=0;
END;
(*------------------ Procedure New_Key_Int -------------------------------*)
PROCEDURE New_Key_Int;interrupt;
VAR temp1,temp2,temp3:word;
test:string;
BEGIN
asm
sti {re-enable interrups }
in al, KEY_BUFFER {get the key that was pressed}
xor ah,ah {zero out upper 8 bits of AX}
mov raw_key, ax {store the key in global}
in al, KEY_CONTROL {set the control register}
or al, 82h {set the proper bits to reset the FF}
out KEY_CONTROL,al {send the new data back to the control register}
and al,7fh
out KEY_CONTROL,al {complete the reset}
mov al,20h
out INT_CONTROL,al {re-enable interrupts}
end;
CASE raw_key OF
MAKE_UP:key_table[INDEX_UP]:= 1;
MAKE_DOWN:key_table[INDEX_DOWN]:=1;
MAKE_RIGHT:key_table[INDEX_RIGHT]:=1;
MAKE_LEFT:key_table[INDEX_LEFT]:=1;
BREAK_UP:key_table[INDEX_UP]:=0;
BREAK_DOWN:key_table[INDEX_DOWN]:=0;
BREAK_RIGHT:key_table[INDEX_RIGHT]:=0;
BREAK_LEFT:key_table[INDEX_LEFT]:=0;
ELSE pressed:=true;
END;
bloodon:=false;
if (raw_key=1) THEN
BEGIN
done:=1;
END
ELSE
if (raw_key=57) THEN
begin
door_x := trunc(player_x + cos(6.28*player_view_angle/ANGLE_360)*6*15);
door_y := trunc(player_y + sin(6.28*player_view_angle/ANGLE_360)*6*15);
x_cell := (door_x DIV CELL_X_SIZE);
y_cell := (door_y DIV CELL_Y_SIZE);
IF ((x_cell=49) AND (y_cell=52)) OR ((x_cell=49) AND (y_cell=57)) OR
((x_cell=50) AND (y_cell=60)) THEN world[y_cell,x_cell]:=0;
IF (x_cell=61) AND (y_cell=62) THEN
BEGIN
fade;
cls;
viewpcxfile('title.pcx');
setintvec(KEYBOARD_INT, Old_Key_Isr); {Get Normal Keyboard Interrupt}
blit_string(10,100,4,'YOU HAVE FOUND A WALDO',TRUE);
blit_string(10,110,4,'BUT NOT THE ONE WITHOUT SHOES',TRUE);
blit_string(10,120,4,'MAYBE HE''S ON THE NEXT LEVEL!!!',TRUE);
blit_string(10,130,4,'PRESS ENTER TO CONTINUE',TRUE);
REPEAT
UNTIL keypressed;
done:=1;
END;
IF (x_cell=58) AND (y_cell=62) THEN
BEGIN
IF gatesdead THEN world[y_cell,x_cell]:=0;
END
ELSE
if (world[y_cell,x_cell] = 9) OR (world[y_cell,x_cell] = 10) THEN
world[y_cell,x_cell]:=0;
IF world[y_cell,x_cell]>10 THEN hit_guy(x_cell,y_cell);
hand.cur_frame:=2;
hancount:=0;
end;
gettime(temp1,temp2,newtime,temp3);
IF newtime-lasttime>1 THEN BEGIN lasttime:=newtime; code:='' END;
IF (pressed) AND (raw_key=19) THEN
IF step_length=50 THEN step_length:=30 ELSE step_length:=50;
IF pressed AND (raw_char(raw_key)>'0') THEN
BEGIN
pressed:=false;
gettime(temp1,temp2,newtime,temp3);
lasttime:=newtime;
insert(raw_char(raw_key),code,length(code)+1);;
END;
END;
(*----------------- Procedure do_code -------------------------------------*)
Procedure do_code;
VAR temp1,temp2,temp3:word;
BEGIN
IF code='canttouchthis' THEN
BEGIN
code:='';
touch:=not(touch);
gettime(temp1,temp2,lasttime,temp3);
END;
IF code='pong' THEN
BEGIN
code:='';
pong_main;
dseg:=seg(double_buffer^); {Get segment of buffer}
doff:=ofs(double_buffer^);
viewpcxfile('panel.pcx');
END;
IF code='rambo' THEN
BEGIN
code:='';
rambo:=not(rambo);
gettime(temp1,temp2,lasttime,temp3);
END;
IF code='lizard' THEN
BEGIN
code:='';
lizard:=not(lizard);
gettime(temp1,temp2,lasttime,temp3);
END;
IF code='sniper' THEN
BEGIN
code:='';
sniper:=not(sniper);
gettime(temp1,temp2,lasttime,temp3);
END;
IF rambo THEN blit_string_d(70,10,10,'UNLIMITED AMMO');
IF touch THEN blit_string_d(70,20,10,'INVINCIBLE');
IF sniper THEN blit_string_d(70,30,10,'ONE-HIT KILLS');
IF lizard THEN
BEGIN
IF life<100 THEN life:=life+1;
blit_string_d(70,40,10,'REGENERATION');
END;
END;
(*-------------------- Proedure do_map ------------------------------------*)
Procedure do_map(VAR x,y:INTEGER);
VAR c1,c2:INTEGER;
BEGIN
FOR c1:=-20 TO 19 DO
FOR c2:=-19 TO 20 DO
IF (c1+y<65) AND (c1+y>0) AND (c2+x>0) AND (c2+x<65) THEN
BEGIN
IF world[c1+y,c2+x]>8 THEN plot_pixel_fast(269+c1,175+c2,3)
ELSE IF world[c1+y,c2+x]>0 THEN plot_pixel_fast(269+c1,175+c2,4)
ELSE plot_pixel_fast(269+c1,175+c2,0);
END
ELSE plot_pixel_fast(269+c1,175+c2,0);
plot_pixel_fast(269,175,10);
END;
(*---------------------- Procedure Global_Init --------------------------*)
PROCEDURE global_init;
VAR spriteim:pcximage;
BEGIN
check_mem(spriteim,64000);
loadpcxfile('waldo.pcx',spriteim);
Sprite_Init(waldo,0,0,0,0,0,0,64,64);
Get_sprite(spriteim,waldo,1,0,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('gates.pcx',spriteim);
Sprite_Init(gates,0,0,0,0,0,0,64,64);
Get_sprite(spriteim,gates,1,0,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('monster.pcx',spriteim);
Sprite_Init(monster,0,0,0,0,0,0,64,64);
Get_sprite(spriteim,monster,1,0,0);
Get_sprite(spriteim,monster,2,1,0);
Get_sprite(spriteim,monster,3,2,0);
Get_sprite(spriteim,monster,4,3,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('wall3.pcx',spriteim);
Sprite_Init(sprite,0,0,0,0,0,0,64,64);
Get_sprite(spriteim,sprite,1,0,0);
Get_sprite(spriteim,sprite,2,1,0);
Get_sprite(spriteim,sprite,3,2,0);
Get_sprite(spriteim,sprite,4,3,0);
Get_sprite(spriteim,sprite,5,0,1);
Get_sprite(spriteim,sprite,6,1,1);
Get_sprite(spriteim,sprite,7,2,1);
Get_sprite(spriteim,sprite,8,3,1);
Get_sprite(spriteim,sprite,9,0,2);
Get_sprite(spriteim,sprite,10,1,2);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('light.pcx',spriteim);
Sprite_Init(light,0,0,0,0,0,0,50,45);
Get_sprite(spriteim,light,1,0,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('blood.pcx',spriteim);
Sprite_Init(blood,110,40,0,0,0,0,64,64);
Get_sprite(spriteim,blood,1,0,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('dagger.pcx',spriteim);
sprite_init(hand,150,55,0,0,0,0,108,101);
get_sprite(spriteim,hand,1,0,0);
get_sprite(spriteim,hand,2,1,0);
freemem(spriteim,64000);
check_mem(spriteim,64000);
loadpcxfile('arrow.pcx',spriteim);
Sprite_Init(arrow,78,170,0,0,0,0,13,13);
Get_sprite_coord(spriteim,arrow,1,0,0);
Get_sprite_coord(spriteim,arrow,2,14,0);
Get_sprite_coord(spriteim,arrow,3,28,0);
Get_sprite_coord(spriteim,arrow,4,41,0);
freemem(spriteim,64000);
check_mem(floor,64000);
loadpcxfile('back.pcx',floor);
Load_World('level1.dat');
life:=100;
step_length:=30;
pressed:=false;
loadvocfile('light.voc',lights);
loadvocfile('ugh.voc',ugh);
viewpcxfile('panel.pcx');
sprite.cur_frame := 1;
sprite.x := 0;
sprite.y := 0;
player_x:=53*64+25;
player_y:=14*64+25;
player_view_angle:=ANGLE_60;
code:='';
rambo:=false;
touch:=false;
lizard:=false;
sniper:=false;
lcounter:=20;
lx:=RANDOM(320);
light.y:=1;
behind_sprite_VB(arrow);
gatesdead:=false;
enmove:=false;
END;
PROCEDURE do_light;
BEGIN
IF lcounter=0 THEN
BEGIN
lx:=RANDOM(320);
lcounter:=40;
END;
IF lcounter=4 THEN
play_sound(lights);
IF lcounter<4 THEN
BEGIN
light.x:=lx;
draw_sprite_f(light)
END;
lcounter:=lcounter-1;
END;
(*---------------- PROCEDURE MAIN --------------------------------------*)
PROCEDURE main;
VAR x_sub_cell,y_sub_cell:INTEGER;
holder,dx,dy:real;
test:string;
BEGIN
global_init;
Draw_Ground;
Ray_Caster(player_x,player_y,player_view_angle);
show_double_buffer_h;
setintvec(KEYBOARD_INT, ADDR(New_Key_Int));
while done<>1 DO
BEGIN
if Get_Input=1 THEN
begin
dx:=0; dy:=0;
if (key_table[INDEX_RIGHT]=1) THEN
BEGIN
player_view_angle:=player_view_angle-ANGLE_6;
if (player_view_angle<ANGLE_0) THEN
player_view_angle:=ANGLE_360;
END
else
if (key_table[INDEX_LEFT]=1) THEN
BEGIN
player_view_angle:=player_view_angle+angle_6;
if (player_view_angle>=ANGLE_360) THEN
player_view_angle:=ANGLE_0;
END;
holder:=6.28*player_view_angle/ANGLE_360;
if (key_table[INDEX_UP]=1) THEN
BEGIN
dx:=(cos(holder)*STEP_LENGTH);
dy:=(sin(holder)*STEP_LENGTH);
END
else
if (key_table[INDEX_DOWN]=1) THEN
BEGIN
dx:=(-cos(holder)*STEP_LENGTH);
dy:=(-sin(holder)*STEP_LENGTH);
END;
player_x:= trunc((player_x+dx));
player_y:= trunc((player_y+dy));
x_cell := (player_x DIV CELL_X_SIZE);
y_cell := (player_y DIV CELL_Y_SIZE);
x_sub_cell := player_x MOD CELL_X_SIZE;
y_sub_cell := player_y MOD CELL_Y_SIZE;
if dx>0 THEN
BEGIN
if ( (world[y_cell,x_cell+1] <> 0) AND
(x_sub_cell > (CELL_X_SIZE-OVERBOARD)))
THEN
BEGIN
player_x:=player_x-(x_sub_cell-(CELL_X_SIZE-OVERBOARD ));
END;
END
else
BEGIN
if ( (world[y_cell,x_cell-1] <> 0) AND
(x_sub_cell < (OVERBOARD) ) ) THEN
BEGIN
player_x:=player_x+ (OVERBOARD-x_sub_cell) ;
END;
END;
if (dy>0 ) THEN
BEGIN
if ( (world[y_cell+1,x_cell] <> 0) AND
(y_sub_cell > (CELL_Y_SIZE-OVERBOARD))) THEN
BEGIN
player_y:=player_y-(y_sub_cell-(CELL_Y_SIZE-OVERBOARD ));
END;
END
else
BEGIN
if ( (world[y_cell-1,x_cell] <> 0) AND
(y_sub_cell < (OVERBOARD) ) ) THEN
BEGIN
player_y:= player_y+(OVERBOARD-y_sub_cell);
END
end;
end;
Draw_Ground;
do_light;
dg:=false;
Ray_Caster(player_x,player_y,player_view_angle);
IF dg THEN Guy_CASTER(player_x,player_y,player_view_angle);
IF bloodon THEN draw_sprite(blood);
do_code;
x_cell := (player_x DIV CELL_X_SIZE);
y_cell := (player_y DIV CELL_Y_SIZE);
do_map(x_cell,y_cell);
IF ((player_view_angle<=240) OR (player_view_angle>=1680))
AND (arrow.cur_frame<>1) THEN
BEGIN
erase_sprite_VB(arrow);
arrow.cur_frame:=1;
behind_sprite_VB(arrow);
draw_sprite_VBF(arrow);
END;
IF (player_view_angle>=720) AND (player_view_angle<=1200)
AND (arrow.cur_frame<>2) THEN
BEGIN
erase_sprite_VB(arrow);
arrow.cur_frame:=2;
behind_sprite_VB(arrow);
draw_sprite_VBF(arrow);
END;
IF (player_view_angle>240) AND (player_view_angle<720)
AND (arrow.cur_frame<>3) THEN
BEGIN
erase_sprite_VB(arrow);
arrow.cur_frame:=3;
behind_sprite_VB(arrow);
draw_sprite_VBF(arrow);
END;
IF (player_view_angle>1200) AND (player_view_angle<1680)
AND (arrow.cur_frame<>4) THEN
BEGIN
erase_sprite_VB(arrow);
arrow.cur_frame:=4;
behind_sprite_VB(arrow);
draw_sprite_VBF(arrow);
END;
IF (life<1) OR (life>100) THEN done:=1;
str(life:3,test);
test:=test+'%';
IF step_length=30 THEN blit_string_d(200,10,10,'Run Mode Off')
ELSE blit_string_d(200,10,10,'Run Mode On');
IF (life>0) AND (life<=100) THEN blit_string(9,173,4,test,false);
IF hand.cur_frame=2 THEN hancount:=hancount+1;
IF hancount=3 THEN hand.cur_frame:=1;
draw_sprite_f(hand);
show_double_buffer_h;
enmove:=false;
END;
fade;
free_scale_data;
setintvec(KEYBOARD_INT, Old_Key_Isr);
freemem(tan_table,6*angle_360);
freemem(inv_tan_table,6*angle_360);
freemem(y_step,6*angle_360);
freemem(x_step,6*angle_360);
freemem(cos_table,6*angle_360);
freemem(inv_cos_table,6*angle_360);
freemem(inv_sin_table,6*angle_360);
textmode(3);
END;
(*-------------------- Proceudre Opening --------------------------------*)
PROCEDURE opening;
VAR counter:INTEGER;
holder:char;
BEGIN
clrscr;
Randomize;
textcolor(white);
textbackground(blue);
gotoxy(1,1);
write(' Cave Dweller- Beta v',RANDOM(9),'.',RANDOM(9));
write(RANDOM(9),RANDOM(9),RANDOM(9),RANDOM(9),RANDOM(9),
RANDOM(9),' ');
textbackground(black);
gotoxy(1,4);
writeln('Memory Required: 320000');
writeln('Memory Available: ',Memavail);
IF memavail<320000 THEN errors(1);
write('Initializing Black Dog Dos Protected Mode Runtime Interface .');
build_tables;
counter:=1;
REPEAT
delay(300);
write('.');
INC(counter);
UNTIL counter=10;
writeln;
writeln('.....Uhh Sorry Can''t Initialize It, It''s Protected.');
writeln('Initializing Cave Dweller Refresh Daemon [............]');
writeln('By The Way, What Exactly Is A Refresh Daemon?????');
writeln;
writeln;
write('Press Any Key To Continue.');
Repeat Until Keypressed;
holder:=readkey;
init256graph;
END;
(*------------------ Procedure Blit_Char_DB ------------------------------*)
PROCEDURE Blit_Char_DB(xc,yc:INTEGER; c:char; color:INTEGER);
VAR offset,x,y,doff,dseg:INTEGER;
work_char:byte;
bit_mask:byte;
BEGIN
doff:=ofs(double_buffer^);
dseg:=seg(double_buffer^);
work_char:=mem[$f000:$fa6e+ (ord(c) * char_height-1)];
offset := (yc SHL 8) + (yc SHL 6) + xc;
for y:=0 to CHAR_HEIGHT-1 DO
BEGIN
bit_mask:=$80;
for x:=0 to CHAR_WIDTH-1 DO
BEGIN
if (work_char AND bit_mask)<>0 THEN
mem[dseg:doff+offset+x]:=color;
bit_mask:=(bit_mask SHR 1);
END;
offset := offset + SCREEN_WIDTH;
work_char:=mem[$f000:$fa6e+ (ord(c) * char_height)+y];
END;
END;
(*------------------ Procedure Blit_String_DB ------------------------------*)
PROCEDURE Blit_String_DB(x,y,color:INTEGER; word:string);
VAR index:integer;
BEGIN
FOR index:=1 TO length(word) DO
BEGIN
Blit_Char_DB(x+(index SHL 3),y,word[index],color);
END;
END;
(*----------------------- Procedure Build_Path --------------------------*)
procedure buildpath;
var
count : byte;
currangle : real;
begin
currangle := pi;
for count := 0 to 199 do
begin
path[count] := 320 + round(radius*sin(currangle));
{ the sin path _must_ lie on an even number }
{ otherwise the picture will be garbage }
if path[count] mod 2 <> 0 then
if path[count] > 320 then
dec(path[count]) { round down }
else
inc(path[count]); { round up }
{ the path is rounded to the closest even number to 320 }
currangle := currangle + angleinc;
end;
end;
(*--------------------- Procedure Main_Menu ----------------------------*)
Procedure main_menu;
VAR choice,color,lchoice:byte;
get:char;
temp:rgb_color_typ;
begin
setintvec(KEYBOARD_INT, Old_Key_Isr); {Get Normal Keyboard Interrupt}
init_double_buffer; {Initialize Off Screen Buffer}
dseg:=seg(double_buffer^); {Get segment of buffer}
doff:=ofs(double_buffer^); {Get offset of buffer}
check_mem(pcxim,64000); {Check Memory, Available: Allocate; Not: Error}
loadpcxfile('main.pcx',pcxim); {Load pcx file into pcxim}
Sprite_Init(menu,31,8,0,0,0,0,263,26);{Initialize width and posistion}
Get_sprite_coord(pcxim,menu,1,32,8); {Grab sprite from pcxim}
freemem(pcxim,64000); {Give back memory}
randomize;
buildpath;
choice:=1; {initialize menu choice to first one}
asm
xor ax,ax { ; AX := 0 }
mov cx,768 { ; CX := # of palette entries }
mov dx,03C8h { ; DX := VGA Port }
mov si,offset palette { ; SI := palette[0] }
out dx,al { ; send zero to index port }
inc dx { ; inc to write port }
@l1:
mov bl,[si] { ; set palette entry }
shr bl,2 { ; divide by 4 }
mov [si],bl { ; save entry }
outsb { ; and write to port }
dec cx { ; CX := CX - 1 }
jnz @l1 { ; if not done then loop }
mov ax,seg buffer { ; AX := segment of buffer }
mov es,ax { ; ES := AX }
mov di,offset buffer { ; DI := buffer[0] }
mov cx,8109 { ; CX := sizeof(buffer) div 2 }
xor ax,ax { ; AX := 0 }
rep stosw { ; clear every element in buffer to zero}
end;
repeat
asm
mov bx,1 { ; BX := 1 }
mov si,offset path { ; SI := path[0] }
mov cx,16160 { ; CX := # of elements to change }
mov di,offset buffer { ; DI := buffer[0] }
add di,320 { ; DI := buffer[320] (0,1) }
@l2:
mov ax,ds:[di-2] { ; AX := buffer[DI-2] (x-1,y) }
add ax,ds:[di] { ; AX += buffer[DI] (x ,y) }
add ax,ds:[di+2] { ; AX += buffer[DI+2] (x+1,y) }
add ax,ds:[di+320] { ; AX += buffer[DI+320] (x,y+1) }
shr ax,2 { ; AX := AX div 4 (calc average) }
jz @l3 { ; if AX = 0 then skip next line }
dec ax { ; else AX-- }
@l3:
push di { ; save DI }
sub di,ds:[si] { ; DI := (x + or - sin,y-1) }
mov word ptr ds:[di],ax { store AX somewhere one line up }
pop di { ; restore DI }
inc di { ; DI++ }
inc di { ; DI++ (move to next word) }
inc bx { ; BX++ }
cmp bx,320 { ; if bx <> 320 }
jle @l4 { ; then jump to @l4 }
mov bx,1 { ; else BX := 1 (we're on a new line) }
inc si { ; point SI to next element in path }
inc si { ; }
@l4:
dec cx { ; CX-- }
jnz @l2 { ; if CX <> 0 then loop }
end;
for count := 0 to 159 do {set new bottom line}
begin
if random < 0.4 then
delta := random(2)*255;
buffer[101,count] := delta;
buffer[102,count] := delta;
end;
asm
mov si,offset buffer { ; SI := buffer[0] }
mov es,dseg { ; ES := AX }
mov di,doff { ; DI := 0 }
mov dx,100 { ; DX := 100 (# of rows div 2) }
@l5:
mov bx,2 { ; BX := 2 }
@l6:
mov cx,160 { ; CX := 160 (# of cols div 2) }
@l7:
mov al,ds:[si] { ; AL := buffer[si] }
mov ah,al { ; AH := AL (replicate byte) }
mov es:[di],ax { ; store two bytes into video memory }
inc di { ; move to next word in VRAM }
inc di { ; }
inc si { ; move to next word in buffer }
inc si { ; }
dec cx { ; CX-- }
jnz @l7 { ; repeat until done with column }
sub si,320 { ; go back to start of line in buffer }
dec bx { ; BX-- }
jnz @l6 { ; repeat until two columns filled }
add si,320 { ; restore position in buffer }
dec dx { ; DX-- }
jnz @l5 { ; repeat until 100 rows filled }
end;
IF lchoice<>choice THEN {Did the choice change?}
BEGIN
color:=255; {if so change the palette}
temp.red := 25 SHR 2;
temp.green := 80 SHR 2;
temp.blue := 25 SHR 2;
FOR color:=color DOWNTO 252 DO
Set_Palette_Register(color,temp);
temp.red := 10 SHR 2;
temp.green := 220 SHR 2;
temp.blue := 25 SHR 2;
CASE choice OF {highlight new choice}
1: Set_Palette_Register(255,temp);
2: Set_Palette_Register(254,temp);
3: Set_Palette_Register(253,temp);
4: Set_Palette_Register(252,temp);
END;
END;
lchoice:=choice;
IF keypressed THEN get:=readkey; {If key was pressed, get it}
IF get=char($50) THEN INC(choice); {IF up arrow increment choice}
IF get=char($48) THEN DEC(choice); {IF down arrow decrement choice}
IF choice<1 THEN choice:=4; {IF out of limits loop}
IF choice>4 THEN choice:=1;
IF get<>chr(13) THEN get:=' '; {IF input not enter clear it}
draw_sprite_f(menu); {Draw Title on Screen, Over flames}
blit_string_db(90,60,255,'START GAME'); {Write Menu Choices}
blit_string_db(90,70,254,'SAVE GAME');
blit_string_db(90,80,253,'LOAD GAME');
blit_string_db(90,90,252,'QUIT');
show_double_buffer_a; {Move buffer to Screen}
until get=chr(13); {Until Enter}
freemem(menu.frames[1],263*26); {Deallocate Sprite Memory}
fade;
cls;
IF choice=1 THEN main; {Start Game}
end;
{------------------- MAIN PROGRAM ---------------------}
BEGIN
init_sound;
opening;
main_menu;
{main;}
fade;
END.